package org.particlethink.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.github.pagehelper.PageInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.particlethink.auth.DefaultUser;
import org.particlethink.entry.BillStatus;
import org.particlethink.model.Bill;
import org.particlethink.model.User;
import org.particlethink.request.CreateBillRequest;
import org.particlethink.request.ReasonRequest;
import org.particlethink.response.*;
import org.particlethink.service.reconciliation.ProjectUserImpl;
import org.particlethink.service.reconciliation.SupplierUserImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Tag(name = "对账")
@RestController
@RequestMapping("/bill")
public class BillController {
    @Autowired
    ProjectUserImpl projectUserSvc;
    @Autowired
    SupplierUserImpl supplierUserSvc;
    @Autowired
    ResourceLoader resourceLoader;

    @Operation(summary = "对账单列表")
    @GetMapping
    public BaseResponse<PageInfo<BillResponse>> List(
            @Parameter(description = "管理层级 string")
            @RequestParam(value = "managementLevel", required = false)
            String managementLevel,

            @Parameter(description = "项目Id(合同买受方) Integer")
            @RequestParam(value = "projectId", required = false)
            Integer projectId,


            @Parameter(description = "合同出售方 String")
            @RequestParam(value = "supplierName", required = false)
            String supplierName,

            @Parameter(description = "创建人 String")
            @RequestParam(value = "creatorName", required = false)
            String creatorName,


            @Parameter(description = "状态 int 1:待确认;2:供应商异议;3:已确认;4:已作废")
            @RequestParam(value = "status", required = false)
            BillStatus status,

            @Parameter(description = "对账周期（时间点） string yyyy-MM-dd HH:mm:ss")
            @RequestParam(value = "billAt", required = false)
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
            Date billAt,


            @Parameter(description = "创建开始时间 string")
            @RequestParam(value = "createStart", required = false)
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
            Date createStart,
            @Parameter(description = "创建结束时间 string")
            @RequestParam(value = "createEnd", required = false)
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
            Date createEnd,
            @Parameter(description = "搜索key string")
            @RequestParam(value = "searchKey", required = false)
            String searchKey,

            @Parameter(description = "页码 int")
            @RequestParam(value = "pageNum", required = false)
            Integer pageNum,
            @Parameter(description = "每页数量 int")
            @RequestParam(value = "pageSize", required = false)
            Integer pageSize
    ) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();
        User user = defaultUser.getUser();

        PageInfo<BillResponse> noBillResponses = projectUserSvc.queryNo(user,searchKey, status);

        if (noBillResponses != null && !noBillResponses.getList().isEmpty()) {
            return BaseResponse.success(noBillResponses);
        }


//        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//        Integer userId = (Integer) authentication.getDetails();
        PageInfo<BillResponse> billResponses = projectUserSvc.billList(
                user,
                managementLevel,
                projectId,
                supplierName,
                creatorName,
                status,
                billAt,
                createStart,
                createEnd,
                searchKey,
                pageNum,
                pageSize
        );
        return BaseResponse.success(billResponses);
    }

    @Operation(summary = "对账单导出")
    @GetMapping("/export")
    public void export(
            @Parameter(description = "管理层级 string")
            @RequestParam(value = "managementLevel", required = false)
            String managementLevel,

            @Parameter(description = "项目id(合同买受方) Integer")
            @RequestParam(value = "projectId", required = false)
            Integer projectId,


            @Parameter(description = "合同出售方 String")
            @RequestParam(value = "supplierName", required = false)
            String supplierName,

            @Parameter(description = "创建人 String")
            @RequestParam(value = "creatorName", required = false)
            String creatorName,


            @Parameter(description = "状态 int 1:待确认;2:供应商异议;3:已确认;4:已作废")
            @RequestParam(value = "status", required = false)
            BillStatus status,

            @Parameter(description = "对账周期（时间点） string yyyy-MM-dd HH:mm:ss")
            @RequestParam(value = "billAt", required = false)
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
            Date billAt,


            @Parameter(description = "创建开始时间 string")
            @RequestParam(value = "createStart", required = false)
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
            Date createStart,
            @Parameter(description = "创建结束时间 string")
            @RequestParam(value = "createEnd", required = false)
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
            Date createEnd,


            HttpServletResponse response
    ) throws IOException {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();
        User user = defaultUser.getUser();
        List<BillExportResponse> billResponses = projectUserSvc.exportBill(
                user,
                managementLevel,
                projectId,
                supplierName,
                creatorName,
                status,
                billAt,
                createStart,
                createEnd
        );


        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("对账单", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        EasyExcel.write(response.getOutputStream(), BillExportResponse.class).sheet("模板").doWrite(billResponses);

    }

    @Operation(summary = "对账单详情")
    @GetMapping("/{id}")
    public BaseResponse<BillDetailResponse> Show(@PathVariable("id") Integer id) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();
        User user = defaultUser.getUser();

        BillDetailResponse batchPlanDetailResponse = projectUserSvc.billDetail(user,id);
        return BaseResponse.success(batchPlanDetailResponse);
    }


    @Operation(summary = "创建对账单")
    @PostMapping
    public BaseResponse<String> Create(@RequestBody List<CreateBillRequest> requests) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Integer userId = (Integer) authentication.getDetails();
        DefaultUser user = (DefaultUser) authentication.getPrincipal();

        //todo 从用户获取项目id

        requests.forEach(request -> {
            Bill bill = new Bill(
                    user.getProjectId(),
                    request.getNo(),
                    request.getDeductionAmount(),
                    request.getDeductionReason(),
                    request.getRewardAmount(),
                    request.getRewardReason(),
                    request.getStartAt(),
                    request.getEndAt(),
                    request.getSupplierId(),
                    userId,
                    new Date()
            );
            bill.setStatus(BillStatus.UnConfirmed);

            projectUserSvc.createBill(bill, request.getDeliverIds());
        });

        return BaseResponse.success("");
    }

    @Operation(summary = "作废对账单 撤回")
    @PostMapping("/{id}/discard")
    public BaseResponse<String> discard(@PathVariable("id") Integer id) {
//        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//        Integer userId = (Integer) authentication.getDetails();
//        if (!UserService.IsProjector(userId)) {
//            throw new NoPermissionException();
//        }
        projectUserSvc.discardBill(id);


        return BaseResponse.success("");
    }

    @Operation(summary = "再次发起对账单")
    @PostMapping("/{id}/reCreate")
    public BaseResponse<String> reCreate(@PathVariable("id") Integer id) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();
        User user = defaultUser.getUser();
        projectUserSvc.reCreateBill(user.getProjectIds(), id);


        return BaseResponse.success("");
    }


    @Operation(summary = "异议对账结果")
    @PostMapping("/{id}/objection")
    public BaseResponse<String> Objection(
            @PathVariable("id") Integer id,
            @Parameter(description = "reason")
            @RequestBody ReasonRequest reason
    ) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();
        User user = defaultUser.getUser();

        this.supplierUserSvc.objectionBill(user.getSupplierIds(), id, reason);


        return BaseResponse.success("");
    }


    @Operation(summary = "确认对账结果")
    @PostMapping("/{id}/confirm")
    public BaseResponse<String> confirm(
            @PathVariable("id") Integer id,
            @Parameter(description = "reason")
            @RequestBody ReasonRequest reasonBody
    ) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();
        User user = defaultUser.getUser();
        this.supplierUserSvc.confirmedBill(user.getSupplierIds(), id, reasonBody);


        return BaseResponse.success("");
    }

    @Operation(summary = "下载")
    @GetMapping("/{id}/download")
    public void download(@PathVariable("id") Integer id, HttpServletResponse response) throws IOException {


        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();
        User user = defaultUser.getUser();

        BillDownloadResponse downloadResponse = this.projectUserSvc.download(user, id);


        AtomicInteger count = new AtomicInteger(0);

        List<BillDownloadMaterialResponse> materials = downloadResponse.getMaterials();


        materials = materials.stream().map(item -> {
            item.setIndex(count.incrementAndGet() + "");
            return item;
        }).collect(Collectors.toList());


//第四步：导出文件设置
// 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
// {} 代表普通变量 {.} 代表是list的变量
// 这里模板 删除了list以后的数据，也就是统计的这一行
// template/模板.xlsx在resource下面的


        Resource resource = resourceLoader.getResource("classpath:" + "bill_template.xlsx");

        try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(resource.getInputStream()).build()) {

            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");

            String fileName = URLEncoder.encode("对账单2", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");


            WriteSheet writeSheet = EasyExcel.writerSheet().build();

            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(materials, fillConfig, writeSheet);

            // 写入list之前的数据
            Map<String, Object> map = new HashMap<>();
            map.put("projectName", downloadResponse.getProjectName());
            map.put("supplierName", downloadResponse.getSupplierName());
            map.put("startAt", downloadResponse.getStartAt());
            map.put("endAt", downloadResponse.getEndAt());
            map.put("deductionAmount", downloadResponse.getDeductionAmount());
            map.put("deductionReason", downloadResponse.getDeductionReason());
            map.put("rewardAmount", downloadResponse.getRewardAmount());
            map.put("rewardReason", downloadResponse.getRewardReason());

            excelWriter.fill(map, writeSheet);
        }
    }


    //小程序
    @Operation(summary = "对账单状态对应数量")
    @GetMapping("/status_count")
    public BaseResponse<BillStatusCountResponse> statusCount(
    ) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        DefaultUser defaultUser = (DefaultUser) authentication.getPrincipal();
        User user = defaultUser.getUser();

        List<Integer> supplierIds = user.getSupplierIds();
        if (supplierIds == null || supplierIds.isEmpty()) {
            return BaseResponse.success(new BillStatusCountResponse(0, 0));
        }
        List<Integer> projectIds = user.getProjectIds();

        BillStatusCountResponse billStatusCountResponse = supplierUserSvc.countOrdersByStatus(supplierIds,projectIds);

        return BaseResponse.success(billStatusCountResponse);
    }
}
